package com.dau.system.config.shiro;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.dau.common.constants.CommConstants;
import com.dau.entity.system.permission.SysPermission;
import com.dau.entity.system.user.SysUser;
import com.dau.entity.system.user.UserProfile;
import com.dau.service.system.permission.SysPermissionService;
import com.dau.service.system.user.SysRoleService;
import com.dau.service.system.user.SysUserService;
import com.dau.system.config.jwt.JwtToken;
import com.dau.system.config.jwt.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.NonNull;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 权限绑定校验
 *
 * @author tzj
 * @date 2024/11/13
 */
@Slf4j
public class MyRealm extends AuthorizingRealm implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    /**
     * 根据token判断此Authenticator是否使用该realm
     * 必须重写不然shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    /**
     * 只有当需要检测用户权限的时候才会调用此方法，例如 checkRole,checkPermission 之类的
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("进入角色授权");
        //获取用户信息
        UserProfile profile = ShiroUtil.getProfile();

        //模拟从数据库获取当前用户的角色，通过用户名查询该用户拥有的角色名称
        SysUser sysUser = ((SysUserService) applicationContext.getBean("sysUserService")).getById(profile.getUserId());
        SysRoleService sysRoleService = (SysRoleService) applicationContext.getBean("sysRoleService");
        SysPermissionService sysPermissionService = (SysPermissionService) applicationContext.getBean("sysPermissionService");
        //从数据库获取当前用户的权限，通过用户查询该用户拥有的权限和角色

        List<String> permissionList = sysRoleService.getPermissionByUserId(sysUser.getId());
        if (CommConstants.ADMIN.equals(sysUser.getUserName())){
            permissionList = sysPermissionService.list().stream().map(SysPermission::getCode).collect(Collectors.toList());
        }
        List<String> roleList = sysRoleService.getRoleByUserId(sysUser.getId());
        //设置角色和权限
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //设置角色
        info.addRoles(roleList);
        //设置权限
        info.addStringPermissions(permissionList);

        //获取session
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute("role", roleList);
        System.out.println("授权完成!");
        return info;
    }

    /**
     * 默认使用此方法进行用户名正确与否验证，错误抛出异常即可。
     * 认证信息 (身份验证)
     * Authentication 是用来验证用户身份
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        JwtToken jwt = (JwtToken) token;
        String userId = ((JwtUtils) applicationContext.getBean("jwtUtils")).getClaimByToken((String) jwt.getPrincipal()).getSubject();
        SysUser user = ((SysUserService) applicationContext.getBean("sysUserService")).getById(Integer.parseInt(userId));
        if (user == null) {
            throw new UnknownAccountException("账户不存在！");
        }
        if (ObjectUtil.isNull(user.getStatus()) || CommConstants.ZERO.equals(user.getStatus()) ) {
            throw new LockedAccountException("账户已被锁定！");
        }
        //登录后返回的信息
        UserProfile profile = new UserProfile();
        BeanUtil.copyProperties(user, profile);
        profile.setUserId(user.getId());
        return new SimpleAuthenticationInfo(profile, jwt.getCredentials(), getName());
    }

    /**
     * 设置应用程序上下文
     *
     * @param applicationContext 应用程序上下文
     * @throws BeansException 豆类例外
     */
    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        if (MyRealm.applicationContext == null) {
            MyRealm.applicationContext = applicationContext;
        }
    }
}
